#include "LecteurPhraseAvecArbre.h"
  
#include <stdlib.h>
#include <iostream>
using namespace std;
  
////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
    ls(nomFich), ts() {
}
  
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
    arbre=programme();
    cout << "Syntaxe correcte." << endl;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
    // <programme> ::= debut <seq_inst> fin FIN_FICHIER
  
    sauterSymCour("debut");
    Noeud* si = seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
    return si;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }
  
    NoeudSeqInst* si = new NoeudSeqInst();
    do {
        si->ajouteInstruction(inst());
        sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>"
            || ls.getSymCour() == "si" || ls.getSymCour() == "tantque"
            || ls.getSymCour() == "repeter" || ls.getSymCour() == "pour"
            || ls.getSymCour() == "lire" || ls.getSymCour() == "ecrire" ||
            ls.getSymCour()=="selon");
    // tant que le symbole courant est un debut possible d'instruction...
    return si;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
    // <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instSelon>
    if (ls.getSymCour() == "<VARIABLE>") {
        return affectation();
    } else if (ls.getSymCour() == "tantque") {
        return instTq();
    } else if (ls.getSymCour() == "si") {
        return instSi();
    } else if (ls.getSymCour() == "repeter") {
        return instRepeter();
    } else if (ls.getSymCour() == "pour") {
        return instPour();
    } else if (ls.getSymCour() == "lire") {
        return instLire();
    } else if (ls.getSymCour() == "ecrire") {
        return instEcrire();
    } else if (ls.getSymCour()=="selon") {
        return instSwitch();
    }
    else {
        erreur("<inst>");
    }
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>
  
    testerSymCour("<VARIABLE>");
    Noeud* var = ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    Noeud* exp = expression();
    return new NoeudAffectation(var,exp);
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }
  
    Noeud* ter = facteur();
    while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
        Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
        Noeud* terDroit= terme(); // lecture de l'operande droit
        ter = new NoeudOperateurBinaire(operateur,ter,terDroit); // const. du noeud
    }
    return ter;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme() {
    // <terme> ::= <facteur> {<opMult> <facteur>}
    Noeud* fact = facteur();
  
    while ((ls.getSymCour() == "*") || (ls.getSymCour() == "/")) {
        Symbole op = opMult();
        Noeud* factDroit = facteur();
        fact =  new NoeudOperateurBinaire(op, fact, factDroit);
    }
    return fact;
}
  
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd() {
    // <opAdd>  ::= + | -
    Symbole op;
    if ((ls.getSymCour() == "+") || (ls.getSymCour() == "-")) {
        op = ls.getSymCour();
        ls.suivant();
    } else {
        erreur("<opAdd>");
    }
    return op;
}
  
////////////////////////////////////////////////////////////////////////////////
  
Symbole LecteurPhraseAvecArbre::opMult() {
    // <opMult>  ::= * | /
    Symbole op;
    if ((ls.getSymCour() == "*") || (ls.getSymCour() == "/")) {
        op = ls.getSymCour();
        ls.suivant();
    } else {
        erreur("<opMult>");
    }
    return op;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
  
    Noeud* fact=NULL;
  
    if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>" || ls.getSymCour() == "<CHAINE>") {
        fact=ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
    } else if (ls.getSymCour()=="-") {
        ls.suivant();
        // on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
        fact = new NoeudOperateurUnaire(Symbole("-"), facteur());
    } else if (ls.getSymCour()=="non") {
        ls.suivant();
        // on représente le moins unaire (non facteur) par une soustractin binaire (0 - facteur)
        fact = new NoeudOperateurUnaire(Symbole("non"), facteur());
    }else if (ls.getSymCour()=="(") {
        ls.suivant();
        fact=expression();
        sauterSymCour(")");
    } else
        erreur("<facteur>");
    return fact;
}
  
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
        exit(0); // plus tard, on levera une exception
    }
}
  
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
}
  
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
            << ls.getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
// Debut 4.3
////////////////////////////////////////////////////////////////////////////////
// Debut 4.2
  
Noeud* LecteurPhraseAvecArbre::expBool() {
    // <expBool> ::= <relation> {<opBool> <relation>}
  
    Noeud* rel = relation();
    while (ls.getSymCour() == "et" || ls.getSymCour() == "ou") {
        Symbole op = opBool();
        Noeud* relDroit = relation();
        rel = new NoeudOperateurBinaire(op, rel, relDroit);
    }
    return rel;
}
  
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBool() {
    // <opBool> ::= et | ou
  
    Symbole op;
    if (ls.getSymCour() == "et" || ls.getSymCour() == "ou") {
        op = ls.getSymCour();
        ls.suivant();
    } else {
        erreur("<opBool>");
    }
    return op;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation() {
    // <relation> ::= <expression> {<opRel> <expression>}
  
    Noeud* exp = expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<"
            || ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        Symbole op = opRel();
        Noeud* expDroite = expression();
        exp = new NoeudOperateurBinaire(op, exp, expDroite);
    }
    return exp;
}
  
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel() {
    // <opRel> ::=  == | != | < | <= | > | >=
      
    Symbole op;
    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<"
            || ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        op = ls.getSymCour();
        ls.suivant();
    } else {
        erreur("<opRel>");
    }
    return op;
}
  
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire() {
    // <opUnaire> ::= - | non
      
    Symbole op;
    if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
        op = ls.getSymCour();
        ls.suivant();
    } else {
        erreur("<opBool>");
    }
    return op;
}
// Fin 4.2
////////////////////////////////////////////////////////////////////////////////
// Debut 4.3
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi() {
    // <instSi> ::= si (<expBool>) <seqInst> { sinon (<expBool>) <seqInst> }
  
    NoeudInstSi* si = new NoeudInstSi();
      
    sauterSymCour("si");
    sauterSymCour("(");
    si->ajouterSi(expBool());
    sauterSymCour(")");
    si->ajouterAlors(seqInst());
     
    while (ls.getSymCour() == "sinonsi" || ls.getSymCour()=="sinon") {
         NoeudInstSi* sinon = new NoeudInstSi();
        
         if(ls.getSymCour()=="sinonsi"){
        ls.suivant();
        sauterSymCour("(");
        sinon->ajouterSi(expBool());
        sauterSymCour(")");
        sinon->ajouterAlors(seqInst());
        si->ajouterSinon(sinon);}
        else if (ls.getSymCour()=="sinon"){
             ls.suivant();
        sinon->ajouterSi(ts.chercheAjoute(Symbole("1")));
        sinon->ajouterAlors(seqInst());
        si->ajouterSinon(sinon);
        }
         
        }
        //ajoutecondition
        

  
    sauterSymCour("finsi");
      
    return si;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq() {
    // <instTq> ::= tantque (<expBool>) <seqInst> fintantque
  
    sauterSymCour("tantque");
    sauterSymCour("(");
    Noeud* cond=expBool();
    sauterSymCour(")");
    Noeud* seq=seqInst();
    sauterSymCour("fintantque");
    return new NoeudInstTq(cond,seq);
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter() {
    // <instRepeter> ::= repeter <seqInst> jusqua (<expBool>)
  
    sauterSymCour("repeter");
    Noeud* seq=seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    Noeud* cond=expBool();
    sauterSymCour(")");
    return new NoeudInstRepeter(cond,seq);
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour(){
    // <instPour> ::= pour (<affectation> <expBool> <expression>) <seqInst> finpour
    sauterSymCour("pour");
    sauterSymCour("(");
	Noeud* init = affectation();
    sauterSymCour(";");
	Noeud* condition = expBool();
    sauterSymCour(";");
	Noeud*  iter= affectation();
    sauterSymCour(")");
    //sauterSymCour("faire");
	NoeudSeqInst* instructions = new NoeudSeqInst();
	do{
		instructions->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour () != "finpour");
    sauterSymCour("finpour");
    return new NoeudInstPour(init,condition,iter,instructions);
}
  
////////////////////////////////////////////////////////////////////////////////


// Fin 4.3
// Debut 4.4
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire() {
    //  <instLire> ::= lire(<variable>)
    NoeudInstLire* var = new NoeudInstLire();
    sauterSymCour("lire");
    sauterSymCour("(");
    testerSymCour("<VARIABLE>");
    var->ajouterSymboleValue(ts.chercheAjoute(ls.getSymCour()));
    sauterSymCour("<VARIABLE>");
    sauterSymCour(")");
    return var;
}
  
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instEcrire() {
    //  <instEcrire> ::= ecrire (<expression> | <chaine>)
    NoeudInstEcrire* ecrit = new NoeudInstEcrire();
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>"
            || ls.getSymCour() == "-" || ls.getSymCour() == "non" || ls.getSymCour() == "(") {
        ecrit->ajouterSymboleValue(expression());
    } else if (ls.getSymCour() == "CHAINE") {
        ls.suivant();
    }
    sauterSymCour(")");
     
    return ecrit;
}
// Fin 2.4

Noeud* LecteurPhraseAvecArbre::instSwitch() {
	//<instSwitch> ::= switch (<VARIABLE>) { case <ENTIER>: <seqInst> break; } [default: <seqInst> break;] endswitch

	vector<Noeud*> ent;
	vector<Noeud*> seq;

	sauterSymCour("selon");
	sauterSymCour("(");
	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour(")");

	while (ls.getSymCour() == "cas") {
		sauterSymCour("cas");
		testerSymCour("<ENTIER>");
		Noeud* entier = ts.chercheAjoute(ls.getSymCour());
		ent.push_back(entier);
		ls.suivant();
		sauterSymCour(":");
		seq.push_back(seqInst());
		sauterSymCour("stop");
		sauterSymCour(";");
	}

	if (ls.getSymCour() == "defaut") {
		ls.suivant();
		sauterSymCour(":");
		seq.push_back(seqInst());
		sauterSymCour("stop");
		sauterSymCour(";");
	}
	sauterSymCour("finselon");
	return new NoeudSwitch(ent, seq, var);
}